import type { EventHook } from '@vueuse/shared';
import type { DeviceInfo } from '@/api/common/deviceInfo';
import { createEventHook } from '@vueuse/core';

import mqtt from 'mqtt/dist/mqtt.js';

import { nanoid } from 'nanoid';

import { computed, ref, shallowRef } from 'vue';
import { isEmpty } from '@/utils/is.utils';

// 默认配置
const DEFAULT_CONFIG = {
  // MQTT 服务器地址
  brokerUrl: import.meta.env.VITE_MQTT_PATH,
  // 主题前缀
  topicPrefix: 'sensor/data',
  // 设备传输唯一标识字段 用于thinsBoard平台解析
  deviceKeyField: 'serialNumber',
  // 设备传输数据字段
  dataKeyField: 'deviceName'
};

// 设备端属性上报
// sensor/data/deviceCode/attributes

// 服务端属性推送
// sensor/data/deviceCode/attribute/update

/**
 * MQTT设备连接Hook
 * @param config 连接配置
 * @returns MQTT操作方法集合
 */
export function useDeviceMqtt(config = DEFAULT_CONFIG) {
  const connectEvent = createEventHook<mqtt.MqttClient>() as EventHook<mqtt.MqttClient>;
  const errorEvent = createEventHook<Error>() as EventHook<Error>;
  const messageEvent = createEventHook<{
    topic: string
    message: Record<string, any>
  }>();

  const mqttClient = shallowRef<mqtt.MqttClient>();
  const isConnected = ref(false);
  const isConnecting = ref(false);
  const connectionError = ref<Error | null>(null);

  const deviceInfo = ref<DeviceInfo>({} as DeviceInfo);
  const activeTopic = computed<string>(() => {
    return `${config.topicPrefix}/${deviceInfo.value.deviceCode}`;
  });

  /**
   * 连接到MQTT服务器
   */
  const connect = () => {
    if (isEmpty(deviceInfo.value)) {
      console.error('设备信息未设置');
      return;
    }
    if (isConnecting.value)
      return;

    isConnecting.value = true;
    connectionError.value = null;

    try {
      const client = mqtt.connect(config.brokerUrl, {
        clientId: nanoid(),
        reconnectPeriod: 5000 // 断线重连间隔
      });

      mqttClient.value = client;

      // 监听连接成功
      client.on('connect', () => {
        console.log('MQTT服务连接成功');
        isConnected.value = true;
        isConnecting.value = false;
        connectEvent.trigger(client);

        // 自动订阅设备主题
        subscribe();

        // 监听消息
        client.on('message', (topic: string, message: any) => {
          const data = parseMqttMessage(message);
          console.log('>>>>收到消息', topic, data);
          messageEvent.trigger({ topic, message: data });
        });
      });

      // 监听错误
      client.on('error', err => {
        console.error('MQTT连接错误:', err);
        connectionError.value = err;
        isConnecting.value = false;
        errorEvent.trigger(err);
      });
    }
    catch (err) {
      console.error('MQTT客户端创建失败:', err);
      connectionError.value
        = err instanceof Error ? err : new Error(String(err));
      isConnecting.value = false;
      errorEvent.trigger(connectionError.value);
    }
  };

  /**
   * 订阅主题
   * @param topic 自定义主题，不提供则使用默认主题
   */
  const subscribe = (topic?: string) => {
    const targetTopic = topic || `${activeTopic.value}/attribute/update`;
    if (mqttClient.value && isConnected.value) {
      mqttClient.value.subscribe(targetTopic, err => {
        if (err) {
          console.error(`订阅主题 ${targetTopic} 失败:`, err);
          errorEvent.trigger(err);
        }
        else {
          console.log(`成功订阅主题: ${targetTopic}`);
        }
      });
    }
  };

  /**
   * 发布消息到主题
   * @param message 消息内容
   * @param topic 自定义主题，不提供则使用默认主题
   */
  const publish = (message: Record<string, any>, topic?: string) => {
    if (
      !mqttClient.value
      || !isConnected.value
      || !deviceInfo.value.deviceCode
    ) {
      console.warn('MQTT客户端未连接或未设置设备信息');
      return false;
    }

    try {
      const targetTopic = topic || `${activeTopic.value}/attributes`;
      const deviceKey = config.deviceKeyField;

      console.log('>>>>上报数据', targetTopic, JSON.stringify(message));

      mqttClient.value.publish(
        targetTopic,
        JSON.stringify({
          [deviceKey]: deviceInfo.value[config.dataKeyField],
          timestamp: new Date().getTime(),
          ...message
        }),
        { qos: 1 },
        err => {
          if (err) {
            console.error('消息发布失败:', err);
            errorEvent.trigger(err);
            return false;
          }
          return true;
        }
      );
    }
    catch (err) {
      console.error('消息发布错误:', err);
      return false;
    }
  };

  /**
   * 注册消息处理回调
   * @param callback 回调函数
   */
  const onMessage = (
    callback: (data: { topic: string, message: Record<string, any> }) => void
  ) => {
    return messageEvent.on(callback);
  };

  /**
   * 断开MQTT连接
   */
  const disconnect = () => {
    if (mqttClient.value) {
      mqttClient.value.end(true, () => {
        console.log('MQTT连接已断开');
      });
      isConnected.value = false;
      connectionError.value = null;
    }
  };

  /**
   * 解析MQTT消息
   * @param message
   * @returns
   */
  const parseMqttMessage = (message: any) => {
    try {
      return JSON.parse(message.toString());
    }
    catch {
      return message;
    }
  };

  const updateConfig = (config: Partial<typeof DEFAULT_CONFIG>) => {
    Object.assign(DEFAULT_CONFIG, config);
    if (mqttClient.value) {
      mqttClient.value.end(true, () => {
        console.log('MQTT连接已断开');
      });
    }
    connect();
  };

  return {
    // 状态
    isConnected,
    isConnecting,
    connectionError,
    deviceInfo,

    // 方法
    connect,
    disconnect,
    subscribe,
    publish,

    // 事件
    onMessage,
    onConnected: connectEvent.on,
    onError: errorEvent.on,

    updateConfig
  };
}
